

local Style = import("../Style/Style.lua");
local Layout = import("../Style/Layout.lua");
local Canvas = import("./Canvas.lua");

local Element = commonlib.inherit(Canvas);

Element:Property("Window");
Element:Property("Parent");
Element:Property("Name");
Element:Property("XmlNode");
Element:Property("TagName");
Element:Property("Style");
Element:Property("DefaultStyle");
Element:Property("DefaultHoverStyle");
Element:Property("DefaultFocusStyle");
Element:Property("Attr");
Element:Property("Directive");
Element:Property("Layout");
Element:Property("Hover", false, "IsHover");
Element:Property("Focus", false, "IsFocus");
Element:Property("ZIndex", 0);
Element:Property("FinishLayout", true, "IsFinishLayout");          -- 是否布局结束
Element:Property("Exist", true, "IsExist");                        -- 默认存在
Element:Property("ExistScrollBar", false, "IsExistScrollBar");     -- 存在滚动条

-- 元素类
function Element:CreateElementClassMap() 
    if (self.__element_class_map__) then return self.__element_class_map__ end
    local parent_element_class_map = self:GetParentElementClassMap();
    self.__element_class_map__ = {};
    if (parent_element_class_map) then setmetatable(self.__element_class_map__, {__index = parent_element_class_map}) end 
    return self.__element_class_map__;    
end

function Element:GetParentElementClassMap()
    local parent = self:GetParent();
    return parent and parent:GetElementClassMap() or commonlib.GetElementClassMap();
end

function Element:GetElementClassMap()
   return self.__element_class_map__ or self:GetParentElementClassMap() or self:CreateElementClassMap();
end

function Element:RegisterElementClass(tagname, class)
    local element_class_map = self:CreateElementClassMap();
    element_class_map[string.lower(tagname)] = class;
end

function Element:RemoveElementClass(tagname)
    local element_class_map = self:CreateElementClassMap();
    element_class_map[string.lower(tagname)] = nil;
end

function Element:GetElementDefaultClass()
    return Element;
end

function Element:GetElementClass(tagname, defaultElementClass)
    local element_class_map = self:GetElementClassMap();
    return element_class_map[string.lower(tagname)] or defaultElementClass or self:GetElementDefaultClass();
end

function Element:CreateElement(xmlnode, window, parent)
    local text = xmlnode.text or "";
    local tagname = xmlnode.name or "";
    text = string.gsub(text, "^%s*", "");
    text = string.gsub(text, "%s*$", "");
    if (tagname == "" and text == "") then return nil end 
    local class = self:GetElementClass(tagname == "" and "text" or tagname);
    return class and class:new():Init(xmlnode, window, parent);
end

function Element:ToColorFromString(color)
    return Style:ToColor(color);
end

function Element:ctor()
    self:SetName("Element");
    self:SetExist(true);

    -- 元素scope
    self.__scope__ = nil;

    -- 子元素
    self.childrens, self.zindex_childrens = {}, {};          

    -- 窗口坐标
    self.x, self.y, self.width, self.height = 0, 0, 0, 0;
end

function Element:InitElement(xmlnode, window, parent)
    -- print(debug.traceback());
    self:SetXmlNode(xmlnode);
    self:SetTagName(xmlnode.name);
    self:SetWindow(window);
    self:SetParent(parent);
    self:SetStyle(Style:new():Init(self));
    self:SetLayout(Layout:new():Init(self));
    self:SetAttr(commonlib.copy(xmlnode.attr or {}));    
    self:GetStyle():SetDefaultStyle(self:GetDefaultStyle());   
    self:GetStyle():SetDefaultHoverStyle(self:GetDefaultHoverStyle());   
    self:GetStyle():SetDefaultFocusStyle(self:GetDefaultFocusStyle());   
    self:GetStyle():SetInlineStyle(self:GetAttr().style);
end

function Element:InitChildrenElement(xmlnode, window, parent)
    for _, subnode in ipairs(xmlnode) do
        self:AddChildren(self:CreateElement(subnode, window, self));
    end
end

function Element:Init(xmlnode, window, parent)
    self:InitElement(xmlnode, window, parent);
    self:InitChildrenElement(xmlnode, window, parent);
    return self;
end

-- xmlnode
function Element:GetXmlNodeText(xmlnode)
    local text = "";
    for _, subnode in ipairs(xmlnode) do
        text = text .. "\n" .. subnode.text;
    end
    return text;
end

function Element:CompileDirective()
    local xmlnode = self:GetXmlNode();
    local attr = self:GetAttr();
    local scope = self:GetScope();
    local indexInParent = self:GetIndexInParent();
    local directive = {["v-attr"] = {}, ["v-on"] = {}};
    local G = self:GetWindow():GetG();
    local isCompileFinish = false;
    for _, key in ipairs(commonlib.keys(attr)) do
        local value = attr[key];
        if (key == "v-if") then
            local expr = "return " .. value;
            directive["v-if"] = G.__new_scope_expr__(expr, nil, scope, function(expr_value)
                self:SetExist(expr_value);
            end);
        elseif (key == "v-model") then
            local attrName = string.sub(key, 8);
            local attrExpr = "return " .. value;
            local keys = commonlib.split(value, ".");
            directive["v-model"] = G.__new_scope_expr__(attrExpr, nil, scope, function(expr_value)
                self:SetAttrValue("value", expr_value);
            end);
            self:SetAttrValue("onchange", function(el, val)
                local subscope, size = scope, #keys;
                for i = 1, size - 1 do subscope = subscope[keys[i]] end
                subscope[keys[size]] = val;
            end);
        elseif (key == "v-for") then
            -- 解析 v-for 表达式
            local vfor = value;
            local inIndex = string.find(vfor, " in ", 1, true);
            if (not inIndex) then 
                local kvexp = string.sub(vfor, 1, inIndex -1);
                local listexp = string.sub(vfor, inIndex + 4);
                local v, k = string.match(kvexp, "(%a%w-)%s*,%s*(%a%w+)");
                if (not v) then v = string.match(kvexp, "(%a%w-)") end
                v = v or "value"
                k = k or "index";
                local expr = "return " .. listexp;
                local clones = {};
                local last_size = 0;
                directive["v-for"] = G.__new_scope_expr__(expr, nil, scope, function(expr_value)
                    local size = 0;
                    if (type(expr_value) == "table") then 
                        size = #expr_value;
                    elseif (type(expr_value) == "number") then
                        size = math.max(0, math.floor(expr_value));
                    else 
                        size = 0;
                    end
                end);
            end 
        elseif (string.sub(key, 1, 7) == "v-bind:") then
            local attrName = string.sub(key, 8);
            local attrExpr = "return " .. value;
            local attrDefaultValue = attr[attrName];
            directive["v-attr"][attrName] = G.__new_scope_expr__(attrExpr, attrDefaultValue, scope, function(expr_value)
                self:SetAttrValue(attrName, expr_value);
            end);
        elseif (string.sub(key, 1, 5) == "v-on:") then
            local attrName = string.sub(key, 6);
            local attrValue = commonlib.loadstring(value, scope);
            self:SetAttrValue(attrName, attrValue);
        end
    end
    -- 文本节点
    if (not xmlnode.name and xmlnode.text) then
        local args = ""
        local text = string.gsub(commonlib.trim(xmlnode.text), "{{(.-)}}", function(code)
            args = args .. ", " .. code;
            return "%s";
        end);
        local expr = string.format([==[return string.format([[%s]]%s)]==], text, args);
        directive["v-text"] = G.__new_scope_expr__(expr, nil, scope, function(expr_value)
            self:SetText(expr_value);
        end);
    end

    for child in self:ChildrenIterator() do
        child:CompileDirective();
    end

    isCompileFinish = true;
    self:SetDirective(directive);
end

-- scirpt env 
function Element:GetScope()
    return self.__scope__ or self:GetParent():GetScope();
end

-- style
function Element:ParseStyle(style)
    return Style:ParseStyle(style);
end

function Element:GetStyleSheet()
    return self:GetParent():GetStyleSheet();
end

function Element:GetStyleValue(style_name, default_value)
    return self:GetStyle():GetValue(style_name, default_value);
end

function Element:GetCurrentStyle()
    return self:GetStyle():GetCurrentStyle();
end

-- 生效元素样式前回调, 
function Element:OnBeforeApplyStyle()
end

-- 生效元素样式
function Element:ApplyStyle()
    self:OnBeforeApplyStyle();
    
    self:GetStyle():ResetStyleSheetStyle();
    self:GetStyleSheet():ApplyElementStyle(self);
    -- 应用样式
    self:GetStyle():ApplyStyle();

    for child in self:ChildrenIterator() do
        child:ApplyStyle();
    end

    self:OnAfterApplyStyle();
end

-- 生效元素样式后
function Element:OnAfterApplyStyle()
    -- 更改最终样式
end

--  layout
function Element:OnBeforeUpdateLayout()
    -- 提取生效样式后即可确定的样式值, 外观相关
    self.__style_font_weight__ = self:GetStyleValue("font-weight");
    self.__style_font_slant__ = self:GetStyleValue("font-style");
    self.__style_font_family__ = self:GetStyleValue("font-family");
    self.__style_font_size__ = self:GetStyle():GetFontSize();
    self.__style_line_height__ = self:GetStyle():GetLineHeight();
    self.__style_color__ = self:GetStyleValue("color", 0xff);
    self.__style_background_color__ = self:GetStyleValue("background-color");
    self.__style_outline_width__ = self:GetStyleValue("outline-width", 0);
    self.__style_outline_color__ = self:GetStyleValue("outline-color");
    self.__style_border_radius__ = self:GetStyleValue("border-radius", 0);
    self.__style_border_color__ = self:GetStyleValue("border-color");
    self.__style_border_width__ = self:GetStyleValue("border-width");
    self.__style_border_top_color__ = self:GetStyleValue("border-top-color");
    self.__style_border_right_color__ = self:GetStyleValue("border-right-color");
    self.__style_border_bottom_color__ = self:GetStyleValue("border-bottom-color");
    self.__style_border_left_color__ = self:GetStyleValue("border-left-color");
end

function Element:OnBeginLayout()
    -- 标记开始
    self:SetFinishLayout(false);
    -- 开始布局
    self:GetLayout():OnBegin();
end

function Element:OnBeforeUpdateChildrenLayout()
    -- 提取布局开始后可以确定的样式, 元素自身尺寸相关
    self:GetLayout():OnBeforeUpdateChildrenLayout();
end

function Element:OnUpdateChildrenLayout()
    for el in self:ChildrenIterator() do el:UpdateLayout() end
end

function Element:OnAfterUpdateChildrenLayout()
    self:GetLayout():OnAfterUpdateChildrenLayout();
end

function Element:OnUpdateLayout()
    self:GetLayout():OnUpdateLayout();
end

function Element:OnEndLayout()
    -- 布局结束
    self:GetLayout():OnEnd();
    -- 标记结束
    self:SetFinishLayout(true);
    -- 布局完成排序元素
    self:SortChildrens();
end

-- 布局更新完成, 递归通知子元素更新自己真实位置
function Element:OnAfterUpdateLayout()
    -- 布局完成回调
    self:GetLayout():OnAfterUpdateLayout();
    
    -- 提取父元素布局完成才能确定的样式值, 主要为位置与尺寸
    local layout = self:GetLayout();
    self.__is_fixed_position__ = layout:IsFixedElement();  -- 是否固定定位
    self.__is_absolute_position = layout:IsAbsoluteElement();
    self.__rel_x__, self.__rel_y__ = layout:GetPos();
    self.__width__, self.__height__ = layout:GetWidthHeight();
    self.__padding_top__, self.__padding_right__, self.__padding_bottom__, self.__padding_left__ = layout:GetPadding();
    self.__border_top_width__, self.__border_right_width__, self.__border_bottom_width__, self.__border_left_width__ = layout:GetBorder();
    self.__content_width__, self.__content_height__ = layout:GetContentWidthHeight();
    self.__real_content_width__, self.__real_content_height__ = layout:GetRealContentWidthHeight();
    self.__is_exist_x_scroll_bar__ = layout:IsCanScrollX();
    self.__is_exist_y_scroll_bar__ = layout:IsCanScrollY();
    self.__is_clip_overflow__ = layout:IsClipOverflow();
    self.__is_exist_scroll_bar__ = self.__is_exist_x_scroll_bar__ or self.__is_exist_y_scroll_bar__;
    self.__scroll_x__ = self.__scroll_x__ or 0;
    self.__scroll_y__= self.__scroll_y__ or 0;

    local scrollbar_thumb_offset = 1;
    local scrollbar_thumb_color = 0xa8a8a8ff;
    local scrollbar_track_size = 10;
    local scrollbar_track_color = 0xf1f1f1ff;
    if (self.__is_exist_y_scroll_bar__) then
        -- scrollbar track
        self.__scrollbar_y_track_color__ = self.__scrollbar_y_track_color__ or scrollbar_track_color;
        self.__scrollbar_y_track_width__ = self.__scrollbar_y_track_width__ or scrollbar_track_size;
        -- scrollbar thumb
        self.__scrollbar_y_thumb_offset__ = self.__scrollbar_y_thumb_offset__ or scrollbar_thumb_offset;
        self.__scrollbar_y_thumb_color__ = self.__scrollbar_y_thumb_color__ or scrollbar_thumb_color;
        self.__scrollbar_y_thumb_width__ = self.__scrollbar_y_track_width__ - 2 * self.__scrollbar_y_thumb_offset__;
        self.__scrollbar_y_thumb_height__ = self.__height__ * self.__content_height__ / self.__real_content_height__;
        self.__scrollbar_y_thumb_x__ = self.__width__ - self.__scrollbar_y_track_width__ + self.__scrollbar_y_thumb_offset__;
        self.__scrollbar_y_thumb_y__ = 0;
        self.__max_scroll_y__ = self.__real_content_height__ - self.__content_height__;
    
    end

    if (self.__is_exist_x_scroll_bar__) then
        -- scrollbar track
        self.__scrollbar_x_track_color__ = self.__scrollbar_x_track_color__ or scrollbar_track_color;
        self.__scrollbar_x_track_height__ = self.__scrollbar_x_track_height__ or scrollbar_track_size;
        -- scrollbar thumb
        self.__scrollbar_x_thumb_offset__ = self.__scrollbar_x_thumb_offset__ or scrollbar_thumb_offset;
        self.__scrollbar_x_thumb_color__ = self.__scrollbar_x_thumb_color__ or scrollbar_thumb_color;
        self.__scrollbar_x_thumb_width__ = self.__width__ * self.__content_width__ / self.__real_content_width__;
        self.__scrollbar_y_thumb_height__ = self.__scrollbar_x_track_height__ - 2 * self.__scrollbar_y_thumb_offset__;
        self.__scrollbar_x_thumb_x__ = 0;
        self.__scrollbar_y_thumb_y__ = self.__height__ - self.__scrollbar_x_track_height__ + self.__scrollbar_y_thumb_offset__;
        self.__max_scroll_x__ = self.__real_content_width__ - self.__content_width__;
    end

    -- 滚动到指定位置
    self:ScrollTo(self.__scroll_x__, self.__scroll_y__);
end


-- 更新布局
function Element:UpdateLayout()
    -- 是否完成布局, 未完成表示正在布局直接退出
    if (not self:IsFinishLayout()) then return end
    -- 布局更新前回调
    self:OnBeforeUpdateLayout();

    -- 开始布局
    self:OnBeginLayout();

    -- 是否需要布局
    if (self:GetLayout():IsNoneLayout()) then return self:OnEndLayout() end

    -- 子元素布局更新前回调
    self:OnBeforeUpdateChildrenLayout();
    
    -- 更新子元素布局
    self:OnUpdateChildrenLayout();

    -- 执行子元素布局后回调
    self:OnAfterUpdateChildrenLayout();

    -- 更新元素布局
    self:OnUpdateLayout();

    -- 结束布局
    self:OnEndLayout();

    -- 元素布局更新后回调
    self:OnAfterUpdateLayout();
end

-- position
function Element:UpdatePosition()
    local layout = self:GetLayout();
    local __x__, __y__ = 0, 0;                          -- 绝对坐标
    local __view_x__, __view_y__ = 0, 0;                -- 视图坐标
    local __scroll_x__, __scroll_y__ = 0, 0;            -- 滚动坐标
    self.__rel_x__, self.__rel_y__ = layout:GetPos();   -- 相对父元素偏移量
    if (layout:IsFixedElement() or not self:GetParent()) then
        __x__, __y__ = self:GetWindow():GetWindowPosition();
        __view_x__, __view_y__ = __x__, __y__;
    else
        __x__, __y__ = self:GetParent():GetPosition();
        __view_x__, __view_y__ = self:GetParent():GetViewPosition();
        __scroll_x__, __scroll_y__ = self:GetParent():GetScrollXY();
    end
    self.__x__, self.__y__ = __x__ + self.__rel_x__, __y__ + self.__rel_y__;
    self.__view_x__, self.__view_y__ = __view_x__ + self.__rel_x__ - __scroll_x__, __view_y__ + self.__rel_y__ - __scroll_y__; 
    self.__content_x__ = self.__x__ + self.__padding_left__ + self.__border_left_width__;
    self.__content_y__ = self.__y__ + self.__padding_top__ + self.__border_top_width__;

    -- 递归更新子元素位置
    for child in self:ChildrenIterator() do child:UpdatePosition() end 
end

-- 获取内容位置
function Element:GetContentPosition()
    return self.__content_x__ or self.x, self.__content_y__ or self.y, self.__content_width__ or 0, self.__content_height__ or 0;
end

-- 获取真实内容宽高
function Element:GetRealContentWidthHeight()
    return self.__real_content_width__ or 0, self.__real_content_height__ or 0;
end

-- 获取位置
function Element:GetPosition()
    return self.__x__ or 0, self.__y__ or 0, self.__width__ or 0, self.__height__ or 0;
end

-- 获取视图位置 含滚动偏移
function Element:GetViewPosition()
    return self.__view_x__ or 0, self.__view_y__ or 0, self.__width__, self.__height__ or 0;
end

-- 是否包含点 窗口坐标
function Element:Contain(sx, sy)
    local x, y, w, h = self:GetViewPosition();
    return x <= sx and sx <= (x + w) and y <= sy and sy <= (y + h);
end

-- 获取滚动值
function Element:GetScrollXY()
    return self.__scroll_x__ or 0, self.__scroll_y__ or 0;
end

-- 获取鼠标XY
function Element:GetMouseXY()
    return __mouse_x__ or 0, __mouse_y__ or 0;
end

-- 滚动
function Element:ScrollTo(scrollX, scrollY)
    if (self.__is_exist_y_scroll_bar__) then
        self.__scroll_y__ = math.max(0, math.min(scrollY or 0, self.__max_scroll_y__));
        self.__scrollbar_y_thumb_y__ = self.__scroll_y__ * self.__height__ / self.__real_content_height__; 
    end

    if (self.__is_exist_x_scroll_bar__) then
        self.__scroll_x__ = math.max(0, math.min(scrollX or 0, self.__max_scroll_x__));
        self.__scrollbar_x_thumb_x__ = self.__scroll_x__ * self.__width__ / self.__real_content_width__;
    end
    -- 更新子元素渲染列表
    self:SortChildrens();
    self:UpdatePosition();
end

-- 获取鼠标元素
function Element:GetMouseElement(x, y)
    -- 优先取子元素
    for el in self:EventChildrenIterator() do
        local target_el = el:GetMouseElement(x, y);
        if (target_el) then return target_el end 
    end
    -- 再检测自己
    return self:Contain(x, y) and self or nil;
end

-- 坐标转换
function Element:ScreenXYToWindowXY(sx, sy)
    local windowX, windowY = self:GetWindow():GetWindowPosition();
    return sx - windowX, sy - windowY;
end

function Element:WindowXYToScreenXY(wx, wy)
    local windowX, windowY = self:GetWindow():GetWindowPosition();
    return wx + windowX, wy + windowY;
end

function Element:ScreenXYToElementXY(sx, sy)
    return sx - (self.__view_x__ or 0), sy - (self.__view_y__ or 0);
end

function Element:ElementXYToScreenXY(x, y)
    return x + (self.__view_x__ or 0), y + (self.__view_y__ or 0);
end

-- 是否可见
function Element:IsVisible()
    if (not self:IsExist() or not self:GetLayout():IsVisible()) then return false end 
    local parent = self:GetParent();
    if (parent and parent.__is_clip_overflow__) then
        local x, y, w, h = self.__rel_x__, self.__rel_y__, self.__width__, self.__height__;
        local __scroll_x__, __scroll_y__ = parent.__scroll_x__, parent.__scroll_y__;
        local width, height = parent.__width__, parent.__height__;
        x, y = x - __scroll_x__, y - __scroll_y__;
        return not ((x + w) <= 0 or width <= x or (y + h) <= 0 or height <= y); 
    end

    return true;
end

function Element:Hide()
    self:SetExist(false);
    local parent = self:GetParent();
    if (parent) then parent:SortChildrens() end
end

function Element:Show()
    self:SetExist(true);
    self:ApplyStyle();
    -- (self:GetParent() or self):UpdateLayout();
    self:UpdateLayout();
    self:UpdatePosition();
    local parent = self:GetParent();
    if (parent) then parent:SortChildrens() end
end

function Element:OnRender()
    self:OnBeforeRender();
    self:Render();
    self:OnBeforeRenderChildren();
    self:OnRenderChildren();
    self:OnAfterRenderChildren();
    self:RenderScrollBar();
    self:OnAfterRender();
end

function Element:OnBeforeRender()
end

function Element:OnBeforeRenderChildren()
end

-- 绘制子元素
function Element:OnRenderChildren()
    if (self.__is_clip_overflow__) then
        local x, y, w, h = self:GetPosition();
        self:Save();
        self:DrawRectangle(x, y, w, h, false);
        self:Clip();
        self:Translate(-self.__scroll_x__, -self.__scroll_y__);
    end
    for el in self:RenderChildrenIterator() do
        el:OnRender();
    end
    if (self.__is_clip_overflow__) then
        self:Translate(self.__scroll_x__, self.__scroll_y__);
        self:Restore();
    end
end

function Element:OnAfterRenderChildren()
end

function Element:OnAfterRender()
end

-- render
function Element:Render()
    local x, y, w, h = self:GetPosition();
    local outlineWidth = self.__style_outline_width__;
    local borderRadius = self.__style_border_radius__;
    if (outlineWidth > 0) then x, y, w, h = x - outlineWidth, y - outlineWidth, w + outlineWidth, h + outlineWidth end 
    self:Save();
    if (borderRadius > 0) then
        self:DrawArc(x + borderRadius, y + borderRadius, borderRadius, 0, 360, false);
        self:DrawArc(x + w - borderRadius, y + borderRadius, borderRadius, 0, 360, false);
        self:DrawArc(x + borderRadius, y + h - borderRadius, borderRadius, 0, 360, false);
        self:DrawArc(x + w - borderRadius, y + h - borderRadius, borderRadius, 0, 360, false);
        self:DrawRectangle(x, y + borderRadius, w, h - 2 * borderRadius, false);
        self:DrawRectangle(x + borderRadius, y, w - 2 * borderRadius, h, false);
    else 
        self:DrawRectangle(x, y, w, h, false);
    end
    self:Clip();
    self:RenderOutline();
    self:RenderBackground();
    self:RenderBorder();
    self:RenderContent();
    self:Restore();
end

-- 绘制外框线
function Element:RenderOutline()
    local x, y, w, h = self:GetPosition();
    local outlineWidth, outlineColor = self.__style_outline_width__, self.__style_outline_color__;
    if (not outlineWidth or not outlineColor) then return end
    self:SetBrushColor(outlineColor);
    self:DrawRectangle(x - outlineWidth, y - outlineWidth , w + 2 * outlineWidth, outlineWidth);      -- 上
    self:DrawRectangle(x + w, y - outlineWidth, outlineWidth, h + 2 * outlineWidth);                  -- 右
    self:DrawRectangle(x - outlineWidth, y + h , w + 2 * outlineWidth, outlineWidth);                 -- 下
    self:DrawRectangle(x - outlineWidth, y - outlineWidth, outlineWidth, h + 2 * outlineWidth);       -- 左
end

function Element:RenderBackground()
    local x, y, w, h = self:GetPosition();
    local backgroundColor = self.__style_background_color__;
    local backgroundImage = self.__style_background_image__;
    if (backgroundImage) then
        self:DrawImage(x, y, w, h, backgroundImage.filepath, backgroundColor);
    else
        if (backgroundColor) then 
            self:SetBrushColor(backgroundColor);
        else 
            self:SetBrushColor(0x0);
        end 
        self:DrawRectangle(x, y, w, h);
    end
end

function Element:RenderBorder()
    local x, y, w, h = self:GetPosition();
    local borderWidth, borderColor = self.__style_border_width__, self.__style_border_color__;
    if (borderWidth and borderWidth > 0 and borderColor) then 
        self:SetBrushColor(borderColor);
        self:DrawRectangle(x, y, w, borderWidth);                          -- 上
        self:DrawRectangle(x + w - borderWidth, y , borderWidth, h);       -- 右
        self:DrawRectangle(x, y + h - borderWidth, w, borderWidth);        -- 下
        self:DrawRectangle(x, y , borderWidth, h);                         -- 左
    else 
        borderWidth, borderColor = self.__style_border_top_width__, self.__style_border_top_color__;
        if (borderWidth and borderWidth > 0 and borderColor) then 
            self:SetBrushColor(borderColor);
            self:DrawRectangle(x, y, w, borderWidth); 
        end
        borderWidth, borderColor = self.__style_border_right_width__, self.__style_border_right_color__;
        if (borderWidth and borderWidth > 0 and borderColor) then 
            self:SetBrushColor(borderColor);
            self:DrawRectangle(x + w - borderWidth, y , borderWidth, h); 
        end
        borderWidth, borderColor = self.__style_border_bottom_width__, self.__style_border_bottom_color__;
        if (borderWidth and borderWidth > 0 and borderColor) then 
            self:SetBrushColor(borderColor);
            self:DrawRectangle(x, y + h - borderWidth, w, borderWidth);
        end
        borderWidth, borderColor = self.__style_border_left_width__, self.__style_border_left_color__;
        if (borderWidth and borderWidth > 0 and borderColor) then 
            self:SetBrushColor(borderColor);
            self:DrawRectangle(x, y , borderWidth, h);
        end
    end
end

function Element:RenderScrollBar()
    local x, y, w, h = self:GetPosition();
    if (self.__is_exist_y_scroll_bar__) then
        -- scrollbar track
        self:SetBrushColor(self.__scrollbar_y_track_color__);
        self:DrawRectangle(x + w - self.__scrollbar_y_track_width__, y, self.__scrollbar_y_track_width__, h);
        -- scrollbar thumb
        self:SetBrushColor(self.__scrollbar_y_thumb_color__);
        self:DrawRectangle(x + self.__scrollbar_y_thumb_x__, y + self.__scrollbar_y_thumb_y__, self.__scrollbar_y_thumb_width__, self.__scrollbar_y_thumb_height__);
    end

    if (self.__is_exist_x_scroll_bar__) then
        -- scrollbar track
        self:SetBrushColor(self.__scrollbar_x_track_color__);
        self:DrawRectangle(x, y + h - self.__scrollbar_x_track_height__, w, self.__scrollbar_x_track_height__);
        -- scrollbar thumb
        self:SetBrushColor(self.__scrollbar_x_thumb_color__);
        self:DrawRectangle(x + self.__scrollbar_x_thumb_x__, y + self.__scrollbar_x_thumb_y__, self.__scrollbar_x_thumb_width__, self.__scrollbar_x_thumb_height__);
    end
end

function Element:RenderContent()
end

function Element:ApplyStyleFontToPaint()
    self:SetFontSize(self.__style_font_size__);
    if (self.__style_color__) then self:SetFontColor(self.__style_color__) end 
    self:SetFont(self.__style_font_weight__, self.__style_font_slant__, self.__style_font_family__);
end

function Element:GetLineHeight()
    return self.__style_line_height__ or 0;
end

function Element:GetTextByWidth(text, width, font_size)
	return Element._super.GetTextByWidth(self, text, width, font_size or self.__style_font_size__);
end

-- 获取属性值
function Element:GetAttrValue(attrName, defaultValue)
    local attrValue = self:GetAttr()[attrName];
    if (attrValue == nil) then return defaultValue end
    return attrValue;
end

-- 获取数字属性值
function Element:GetAttrNumberValue(attrName, defaultValue)
    return tonumber(self:GetAttrValue(attrName)) or defaultValue or 0;
end

-- 获取字符串属性值
function Element:GetAttrStringValue(attrName, defaultValue)
    local value = self:GetAttrValue(attrName)
    return (value ~= nil and tostring(value) or defaultValue) or "";
end

-- 获取布尔属性值
function Element:GetAttrBoolValue(attrName, defaultValue)
    local value = self:GetAttrValue(attrName);
    if (type(value) == "boolean") then return value end
    if (type(value) ~= "string") then return defaultValue end
    return value == "true";
end

-- 获取表属性值
function Element:GetAttrTableValue(attrName, defaultValue)
    local value = self:GetAttrValue(attrName);
    return (type(value) == "table" and value or defaultValue) or {};
end

-- 获取函数属性
function Element:GetAttrFunctionValue(attrName, defaultValue)
    local value = self:GetAttrValue(attrName);
    if (type(value) == "function") then return value end 
    if (type(value) == "string") then 
        -- 编译缓存
        value = commonlib.loadstring(value, self:GetScope());
        self:SetAttrValue(attrName, value);
        return value or defaultValue;
    end
    return defaultValue;
end

-- 调用事件函数
function Element:CallAttrFunction(attrName, defaultValue, ...)
    local func = self:GetAttrFunctionValue(attrName, defaultValue);
    if (not func) then return nil end
    return func(self, ...);
end

-- 常用属性
-- 属性ID
function Element:GetAttrId()
    return self:GetAttrStringValue("id");
end

-- 是否禁用
function Element:IsDisabled()
    return self:GetAttrBoolValue("disabled") == true and true or false;
end

-- 元素属性值更新
function Element:OnAttrValueChange(attrName, attrValue, oldAttrValue)
    if (attrName == "class") then 
        self:UpdateLayout();
    end
    if (attrName == "style") then 
        self:GetStyle():SetInlineStyle(attrValue); 
        self:UpdateLayout();
    end
end

-- 设置属性值
function Element:SetAttrValue(attrName, attrValue)
    local attr = self:GetAttr();
    local oldAttrValue = attr[attrName];
    attr[attrName] = attrValue;
    if (oldAttrValue == attrValue) then return end
    self:OnAttrValueChange(attrName, attrValue, oldAttrValue);
end

-- 设置样式值
function Element:SetInlineStyleValue(styleKey, styleValue)
    self:GetStyle():GetInlineStyle()[styleKey] = styleValue;
end

-- children 
function Element:IsExistChildren(children)
    if (not children) then return end
    for index, child in ipairs(self.childrens) do
        if (child == children) then return true, index end 
    end
    return false;
end

function Element:GetChildren(index)
    return self.childrens[index];
end

function Element:RemoveChildren(children)
    local exist, index = self:IsExistChildren(children);
    if (exist) then table.remove(self.childrens, index) end 
end

function Element:AddChildren(children)
    if (not children) then return end
    table.insert(self.childrens, children);
end

-- 上一个兄弟元素
function Element:GetPrevSiblingElement()
    local parentElement = self:GetParent();
    if (not parentElement) then return end
    local prevSiblingElement = nil;
    for i, child in ipairs(parentElement.childrens) do
        if (child == self) then return prevSiblingElement end
        prevSiblingElement = if_else(child:IsExist(), child, prevSiblingElement);
    end
end

-- 下一个兄弟元素
function Element:GetNextSiblingElement()
    local parentElement = self:GetParent();
    if (not parentElement) then return end
    local nextSiblingElement = nil;
    for i = #self.childrens, 1, -1 do
        child = self.childrens[i];
        if (child == self) then return nextSiblingElement end
        nextSiblingElement = if_else(child:IsExist(), child, nextSiblingElement);
    end
end

-- 获取元素位置
function Element:GetChildrenIndex(children)    
    local index = 0;
    for _, child in ipairs(self.childrens) do 
        if (child:IsExist()) then index = index + 1 end
        if (child == children) then return index end 
    end
    return 0;
end

-- 获取元素位置
function Element:GetIndexInParent()
    local parentElement = self:GetParent();
    if (not parentElement) then return 0 end
    return parentElement:GetChildrenIndex(self);
end

-- 排序子元素 z-index 由小到大排列
function Element:SortChildrens()
    commonlib.cleartable(self.zindex_childrens);
    
    for _, el in ipairs(self.childrens) do
        if (el:IsVisible()) then
            local zindex = el:GetZIndex();
            local size = #(self.zindex_childrens);
            local index = 1;
            while (index <= size) do
                local _el = self.zindex_childrens[index];
                if (zindex < _el:GetZIndex()) then break end
                index = index + 1;
            end 
            table.insert(self.zindex_childrens, index, el);
        end
    end
end

-- 默认渲染序 z-index 由小到大迭代
function Element:ChildrenIterator()
    local index = 0;
    return function()
        index = index + 1;
        return self.childrens[index];
    end
end

-- 渲染序子元素迭代器  z-index 由小到大迭代
function Element:RenderChildrenIterator()
    local index = 0;
    return function()
        index = index + 1;
        return self.zindex_childrens[index];
    end
end

-- 事件序 z-index 由大到小迭代
function Element:EventChildrenIterator()
    local size = #(self.zindex_childrens);
    local index = size + 1;
    return function()
        index = index - 1;
        return self.zindex_childrens[index];
    end
end

-- 是否捕获鼠标
function Element:IsMouseCaptured()
    return self:GetMouseCapture() ~= nil;
end

-- 获取鼠标捕获
function Element:GetMouseCapture()
    return self:GetWindow():GetMouseCaptureElement();
end

-- 捕获鼠标
function Element:CaptureMouse()
    if (self:IsMouseCaptured()) then return end 

    local win = self:GetWindow();
    win:SetMouseCaptureElement(self);
    win.SetMouseCaptureWindow(win);
end

-- 释放鼠标捕获
function Element:ReleaseMouse()
	if (self:GetMouseCapture() ~= self) then return end

    local win = self:GetWindow();
    win:SetMouseCaptureElement(nil);
    win.SetMouseCaptureWindow(nil);
end

-- Event
function Element:OnMouseDownCapture()
end
function Element:OnMouseUpCapture()
end
function Element:OnMouseMoveCapture()
end
function Element:OnMouseWheelCapture()
end
function Element:OnMouseCapture()
end
function Element:OnMouse(event)
end
function Element:OnMouseDown(event)
    self:CallAttrFunction("onmousedown", nil, event);
end
function Element:OnMouseUp(event)
    self:CallAttrFunction("onmouseup", nil, event);
end
function Element:OnMouseMove(event)
    self:CallAttrFunction("onmousemove", nil, event);
end
function Element:OnMouseWheel(event)
    self:ScrollTo(self.__scroll_x__, (self.__scroll_y__ or 0) + event:GetMouseWheelDelta());
    self:CallAttrFunction("onmousewheel", nil, event);
end
function Element:OnKeyDown(event)
    self:CallAttrFunction("onkeydown", nil, event);
end
function Element:OnKeyUp(event)
    self:CallAttrFunction("onkeyup", nil, event);
end
function Element:OnChar(event)
    self:CallAttrFunction("onchar", nil, event);
end
function Element:OnClick(event)
    self:CallAttrFunction("onclick", nil, event);
end

-- 失去焦点事件
function Element:OnFocusOut()
    self:CallAttrFunction("onblur", nil);
end

-- 获取焦点事件
function Element:OnFocusIn()
    self:CallAttrFunction("onfocus", nil);
end

-- 获取聚焦元素
function Element:GetFocus()
    return self:GetWindow():GetFocusElement();
end

-- 是否是聚焦元素
function Element:IsFocus()
    return self:GetFocus() == self;
end

-- 元素主动聚焦
function Element:FocusIn()
    self:SetFocus(self);
end

-- 元素主动失去焦点
function Element:FocusOut()
    self:SetFocus(nil);
end

-- 设置聚焦元素
function Element:SetFocus(element)
    local window = self:GetWindow();
    if (not window) then return end
    -- 获取旧焦点
    local focusElement = window:GetFocusElement();
    if (focusElement == element) then return end

    -- 失焦, 设置聚焦元素为空
    window:SetFocusElement(nil);
    if (focusElement) then focusElement:OnFocusOut() end

    -- 聚焦, 再次设置聚焦元素, OnFocusOut 很有可能破坏聚焦元素
    window:SetFocusElement(element);
    if (element) then element:OnFocusIn() end
end

return Element;